﻿#include "RecordManager.h"
#include "../util/TextUtil.h"
#include "../util/SystemHelper.h"
#include "../log/SysLog.h"

RecordManager::RecordManager()
{

}

RecordManager::~RecordManager()
{
}

void RecordManager::Init(int fps, int width, int height)
{
	if (!m_init)
	{
		m_fps = fps;
		m_width = width;
		m_height = height;
		m_pre_frame = fps * 5;
		if (m_pre_frame > 30 * 5)
		{
			m_pre_frame = 30 * 5;
		}
		m_init = true;
	}
}

void RecordManager::Stop()
{
	// 停止线程
	m_run = false;
	if (m_thread.joinable())
	{
		m_thread.join();
	}
	// 录像已存在
	std::unique_lock<std::mutex> _guard(m_record_lock);
	// 关闭所有录像
	for (RECORDS::iterator it = m_record_map.begin(); it != m_record_map.end(); ++it)
	{
		RecordPtr record = it->second;
		if (record)
		{
			record->Stop();
		}
	}
	// 清理录像列表
	m_record_map.clear();
	// 清理预录队列
	while (!m_pre_queue.empty())
	{
		m_pre_queue.pop();
	}
	// 清理视频缓存
	while (!m_image_queue.empty())
	{
		m_image_queue.pop();
	}
	// 初始化标志
	m_init = false;
}

void RecordManager::StartAlarmRecord(std::string id, std::string deviceId, int duration, ALARM_RC_CB cb)
{
	// 视频未初始化
	if (!m_init)
	{
		LOG_WARN("device {} record not init, ignore record.", deviceId);
		return;
	}
	// 正在手动录像
	if (m_event_record)
	{
		LOG_WARN("device {} has event record, ignore record.", deviceId);
		return;
	}
	// 录像已存在
	std::unique_lock<std::mutex> _guard(m_record_lock);
	if (m_record_map.find(id) != m_record_map.end())
	{
		return;
	}
	// 生成录像路径
	std::string path = SystemHelper::get_mutable_instance().GetDeviceRecordPath(deviceId, id);
	// 创建录像对象
	AlarmRecordPtr record = std::make_shared<AlarmRecord>();
	record->SetId(id);
	record->SetDeviceId(deviceId);
	record->SetPath(path);
	record->SetDuration(duration);
	record->SetPreRecord(true);
	record->SetCallback(cb);
	if (!record->Start(m_fps, m_width, m_height, path))
	{
		LOG_WARN("start alarm [{}] record failed: {}", id, path);
		return;
	}
	// 加入录像列表
	m_record_map[id] = record;
}

bool RecordManager::StartManualRecord(std::string id, std::string deviceId, std::string deviceName, int duration, EVENT_RC_CB cb, bool event)
{
	// 视频未初始化
	if (!m_init)
	{
		LOG_WARN("device {} record not init, ignore record.", deviceId);
		return false;
	}
	// 已有手动录像
	if (m_event_record)
	{
		LOG_WARN("device {} has event record, ignore record.", deviceId);
		return false;
	}
	// 录像已存在
	std::unique_lock<std::mutex> _guard(m_record_lock);
	if (m_record_map.find(id) != m_record_map.end())
	{
		return false;
	}
	// 生成手动录像路径
	std::string recordId = TextUtil::get_mutable_instance().GetGuid();
	// 生成录像路径
	std::string path = SystemHelper::get_mutable_instance().GetDeviceRecordPath(deviceId, recordId);
	// 创建录像对象
	ManualRecordPtr record = std::make_shared<ManualRecord>();
	record->SetId(id);
	record->SetRecordId(recordId);
	record->SetDeviceId(deviceId);
	record->SetDeviceName(deviceName);
	record->SetPath(path);
	record->SetDuration(duration);
	record->SetPreRecord(true);
	record->SetCallback(cb);
	if (!record->Start(m_fps, m_width, m_height, path))
	{
		LOG_WARN("start manual [{}] record failed: {}", id, path);
		return false;
	}
	// 加入录像列表
	m_record_map[id] = record;
	// 标识有手动录像
	m_event_record = event;
	LOG_INFO("create device {} event record {} success.", deviceId, id);
	return true;
}

void RecordManager::StopManualRecord(std::string id)
{
	std::unique_lock<std::mutex> _guard(m_record_lock);
	// 没有录像
	if (m_record_map.find(id) == m_record_map.end())
	{
		LOG_WARN("record {} not init, ignore record.", id);
		return;
	}
	RecordPtr temp = m_record_map[id];
	if (!temp)
	{
		return;
	}
	// 停止录像
	ManualRecordPtr record = std::dynamic_pointer_cast<ManualRecord>(temp);
	if (record)
	{
		record->SetRun(false);
	}
	LOG_INFO("set device {} record to stop.", m_deviceId);
}

bool RecordManager::StartManualCapture(std::string id)
{
	std::unique_lock<std::mutex> _guard(m_record_lock);
	// 没有录像
	if (m_record_map.find(id) == m_record_map.end())
	{
		LOG_WARN("record {}  not found, ignore record.", id);
		return false;
	}
	RecordPtr temp = m_record_map[id];
	if (!temp)
	{
		return false;
	}
	// 停止录像
	ManualRecordPtr record = std::dynamic_pointer_cast<ManualRecord>(temp);
	if (record)
	{
		record->SetCapture(true);
	}
	LOG_INFO("start device {} record {} capture.", m_deviceId, id);
	return true;
}

void RecordManager::InputFrame(cv::Mat& frame)
{
	// 视频未初始化
	if (!m_init)
	{
		return;
	}
	// 预录队列检测
	std::unique_lock<std::mutex> _guard(m_queue_lock);
	while (m_pre_queue.size() >= m_pre_frame)
	{
		m_pre_queue.pop();
	}
	// 加入预录队列
	m_pre_queue.push(frame.clone());
	// 加入缓存队列
	m_image_queue.push(frame.clone());
}

bool RecordManager::HasManualRecord()
{
	return m_event_record;
}

void RecordManager::Start()
{
	// 开始运行
	m_run = true;
	// 启动线程
	m_thread = std::thread([&]()->void {
		while (m_run)
		{
			// 获取录像列表
			RECORDS records;
			{
				std::unique_lock<std::mutex> _guard(m_record_lock);
				records = m_record_map;
			}

			// 写入预录图像
			if (records.size() > 0)
			{
				// 获取预录队列
				IMAGE_QUEUE pre_queue;
				{
					std::unique_lock<std::mutex> _guard(m_queue_lock);
					pre_queue = m_pre_queue;
				}
				// 转图像数组
				std::vector<cv::Mat> images;
				while (!pre_queue.empty())
				{
					cv::Mat image = pre_queue.front();
					pre_queue.pop();
					images.push_back(image);
				}
				// 写入预录图像
				for (RECORDS::iterator it = records.begin(); it != records.end(); ++it)
				{
					// 无效的录像信息
					RecordPtr record = it->second;
					if (!record)
					{
						continue;
					}
					// 刚开始且需预录
					if (record->GetFrame() == 0 && record->GetPreRecord())
					{
						// 已写预录数据
						if (record->GetWriteRecord())
						{
							continue;
						}
						// 写入所有预录图像
						for (size_t index = 0; index < images.size(); ++index)
						{
							record->Write(images[index]);
						}
						// 不要再次预录图像
						if (images.size() > 0)
						{
							record->SetWriteRecord(true);
						}
					}
				}
			}

			// 写入最新图像
			while (true)
			{
				// 从队列获取图像
				cv::Mat image;
				bool has_image = false;
				{
					std::unique_lock<std::mutex> _guard(m_queue_lock);
					if (m_image_queue.size() > 0)
					{
						image = m_image_queue.front();
						m_image_queue.pop();
						has_image = true;
					}
				}
				// 无图像数据退出
				if (!has_image)
				{
					break;
				}
				// 已完成录像列表
				std::vector<std::string> finish_records = {};
				// 需删除手动录像
				bool del_event_record = false;
				// 写入预录图像
				for (RECORDS::iterator it = records.begin(); it != records.end(); ++it)
				{
					// 无效的录像信息
					RecordPtr record = it->second;
					if (!record)
					{
						continue;
					}
					// 写入当前录像帧
					record->Write(image);
					// 累计写入帧数量
					record->SetFrame(record->GetFrame() + 1);
					// 获取已录制时长
					int duration = (int)(record->GetFrame() * 1.0 / m_fps);
					// 手动或GPIO录像
					if (record->GetType() == "manual")
					{
						ManualRecordPtr temp = std::dynamic_pointer_cast<ManualRecord>(record);
						if (!record)
						{
							continue;
						}
						// 有手动录像抓拍
						if (temp->GetCapture())
						{
							LOG_INFO("device {} record {} capture ok.", m_deviceId, temp->GetRecordId());
							// 手动主图信息
							DateTime current_time = DateTime::Now();
							std::string image_id = TextUtil::get_mutable_instance().GetGuid();
							std::string image_path = SystemHelper::get_mutable_instance().GetDeviceImagePath(record->GetDeviceId(), image_id);
							// 实时保存图片
							cv::imwrite(image_path, image);
							temp->SetCapture(false);
							// 手动抓拍回调
							EVENT_RC_CB cb = temp->GetCallback();
							if (cb)
							{
								RECORD_INFO recordInfo;
								recordInfo.eventId = temp->GetId();
								recordInfo.image = true;
								recordInfo.recordId = image_id;
								recordInfo.deviceId = temp->GetDeviceId();
								recordInfo.deviceName = temp->GetDeviceName();
								recordInfo.recordPath = image_path;
								recordInfo.startTime = current_time;
								recordInfo.stopTime = current_time;
								recordInfo.duration = 0;
								cb(false, recordInfo);
							}
						}
						// 手动停止或录制超时
						if (!temp->GetRun() || temp->IsTimeout())
						{
							// 标记手动录像移除
							del_event_record = true;
							// 加入录像移除列表
							temp->Stop();
							finish_records.push_back(it->first);
							// 录像录制完成回调
							EVENT_RC_CB cb = temp->GetCallback();
							if (cb)
							{
								RECORD_INFO recordInfo;
								recordInfo.eventId = temp->GetId();
								recordInfo.image = false;
								recordInfo.recordId = temp->GetRecordId();
								recordInfo.deviceId = temp->GetDeviceId();
								recordInfo.deviceName = temp->GetDeviceName();
								recordInfo.recordPath = temp->GetPath();
								recordInfo.startTime = temp->GetBeginTime();
								recordInfo.stopTime = DateTime::Now();
								recordInfo.duration = temp->GetDuration();
								cb(true, recordInfo);
							}
						}
						// 片段录制完成回调
						else if (duration >= temp->GetDuration())
						{
							// 停止录制的视频
							temp->Stop();
							// 录像录制完成回调
							EVENT_RC_CB cb = temp->GetCallback();
							if (cb)
							{
								RECORD_INFO recordInfo;
								recordInfo.eventId = temp->GetId();
								recordInfo.image = false;
								recordInfo.recordId = temp->GetRecordId();
								recordInfo.deviceId = temp->GetDeviceId();
								recordInfo.deviceName = temp->GetDeviceName();
								recordInfo.recordPath = temp->GetPath();
								recordInfo.startTime = temp->GetBeginTime();
								recordInfo.stopTime = DateTime::Now();
								recordInfo.duration = temp->GetDuration();
								cb(false, recordInfo);
							}
							// 建下个新片段
							std::string record_id = TextUtil::get_mutable_instance().GetGuid();
							// 更新录像片段
							temp->SetRecordId(record_id);
							temp->SetBeginTime(DateTime::Now());
							temp->SetFrame(0);
							// 后续片段不预录
							temp->SetPreRecord(false);
							// 新录像文件路径
							std::string file_path = SystemHelper::get_mutable_instance().GetDeviceRecordPath(temp->GetDeviceId(), record_id);
							temp->SetPath(file_path);
							// 开启录像新片段
							if (temp->Start(m_fps, m_width, m_height, file_path))
							{
								LOG_INFO("create device {} piece record {}.", m_deviceId, record_id);
							}
							else
							{
								LOG_WARN("create device {} piece record failed: {}", m_deviceId, file_path);
							}
						}
					}
					// 报警录像完成
					else if (record->GetType() == "alarm" && duration >= record->GetDuration())
					{
						AlarmRecordPtr temp = std::dynamic_pointer_cast<AlarmRecord>(record);
						if (!record)
						{
							continue;
						}
						// 停止录制的视频
						temp->Stop();
						// 加入移除列表
						finish_records.push_back(it->first);
						// 录制完成回调
						ALARM_RC_CB cb = temp->GetCallback();
						if (cb)
						{
							// 录像编码 录像设备 录像路径 录像时长
							cb(temp->GetId(), temp->GetDeviceId(),
								temp->GetPath(), temp->GetDuration());
						}
					}
				}

				// 移除已完成录像文件
				for (size_t index = 0; index < finish_records.size(); ++index)
				{
					std::string id = finish_records[index];
					records.erase(id);
					m_record_map.erase(id);
				}
				// 手动录像被移除
				if (del_event_record)
				{
					m_event_record = false;
				}
			}

			// 让出CPU继续执行
			if (records.size() <= 0)
			{
				std::this_thread::sleep_for(std::chrono::milliseconds(2));
			}
		}
	});
}